import { FieldPacket } from 'mysql2/promise';
import { defaultSqlDriver } from '../../sql/sql';
import jwt from 'jsonwebtoken';
import { Response_Msg, User_Token_info } from '../../public/types';
import utils from '../../public/utils';
import { tokenSecretKeyMap } from '../../public/clientMap';

/**
 * 验证登录用户的函数
 * @async
 * @param {string} username - 用户的名字
 * @param {string} password - 用户的密码
 * @param {string} clientId - 客户端的ID
 * @returns {Promise<Response_Msg>} 返回登录的结果信息
 */
const login = async (
  username: string,
  password: string,
  clientId: string
): Promise<Response_Msg> => {
  const sql = `select id, salt, \`name\`, password from user_info where username = ?`;
  try {
    const [result]: [any[], FieldPacket[]] = await defaultSqlDriver.query(sql, [
      username
    ]);
    if (result.length === 0) {
      return {
        code: 400,
        msg: '用户不存在',
        data: void 0
      };
    }
    const { id, salt, password: dbPassword, name } = result[0];
    const passwordHash = utils.getPasswordHash(password, salt);
    if (passwordHash === dbPassword) {
      const secretKey = utils.getRadomString(32);
      const tokenInfo: User_Token_info = {
        id,
        username,
        clientId
      };
      const token = jwt.sign(tokenInfo, secretKey);
      tokenSecretKeyMap.set(token, secretKey);
      //登录成功
      return {
        code: 200,
        msg: '登录成功',
        data: {
          token,
          userId: id,
          name
        }
      };
    } else {
      return {
        code: 400,
        msg: '账号或密码错误',
        data: void 0
      };
    }
  } catch (error) {
    console.error(error);
  }
  return {
    code: 400,
    msg: '服务器错误',
    data: void 0
  };
};

/**
 * 用户注册的函数
 * @async
 * @param {string} username - 用户的名字
 * @param {string} password - 用户的密码
 * @param {string} name - 昵称
 * @returns {Promise<Response_Msg>} 返回注册的结果信息
 */
const register = async (
  username: string,
  password: string,
  name: string
): Promise<Response_Msg> => {
  //用crypto模块生成密码盐
  const salt = utils.getRadomString(32);
  const sql = `insert into user_info (id, username, password, name, salt) values (?, ?, ?, ?, ?)`;
  //待插入数据
  const insertData = {
    id: utils.generateUserId(),
    salt: salt,
    username,
    password: utils.getPasswordHash(password, salt),
    name,
    create_time: Date.now()
  };
  try {
    //查询是否存在该用户
    const querySql = `select id from user_info where username = ?`;
    const [queryResult]: [any[], FieldPacket[]] = await defaultSqlDriver.query(
      querySql,
      [username]
    );
    if (queryResult.length > 0) {
      return {
        code: 400,
        msg: '用户已存在',
        data: void 0
      };
    }
    await defaultSqlDriver.execute(sql, [
      insertData.id,
      insertData.username,
      insertData.password,
      insertData.name,
      insertData.salt
    ]);
    return {
      code: 200,
      msg: '注册成功',
      data: {
        userId: insertData.id
      }
    };
  } catch (error) {
    console.error(error);
  }
  return {
    code: 500,
    msg: '服务器错误',
    data: void 0
  };
};

/**
 * 搜索
 * @async
 * @param {string} keyWord - 搜索关键词
 * @param {string} clientId - 客户端的ID
 * @param {string} token - 用户的token
 * @returns {Promise<Response_Msg>} 返回搜索结果信息
 */
const searchUser = async (
  userId: string,
  keyWord: string
): Promise<Response_Msg> => {
  // 通过jwt验证用户token
  try {
    const sql = `
      with t1 as (
      select user_id, friend_id
      from friends_info 
      where friend_id = '${userId}' or user_id = '${userId}'
      )
      select 
      t2.id, 
      t2.username,
      t2.\`name\` ,
      (case when t1.user_id is not null or t1.friend_id is not null then 1 else 0 end) as isFriend
      from user_info t2
      left join t1 on t1.friend_id = t2.id or t1.user_id = t2.id 
      where (t2.username = '${keyWord}' or t2.name like '%${keyWord}%') and t2.id <> '${userId}'
    `;
    const [result] = await defaultSqlDriver.query(sql);
    return {
      code: 200,
      msg: '查询成功',
      data: result
    };
  } catch (error) {
    console.error(error);
    return {
      code: 500,
      msg: `服务器错误`,
      data: void 0
    };
  }
};

const addFriend = async (
  userId: string,
  friendId: string
): Promise<Response_Msg> => {
  try {
    const sql = `insert into friends_info (user_id, friend_id) values (?, ?)`;
    await defaultSqlDriver.execute(sql, [userId, friendId]);
    return {
      code: 200,
      msg: `添加成功`,
      data: void 0
    };
  } catch (error) {
    return {
      code: 500,
      msg: `服务器错误`,
      data: void 0
    };
  }
};

/**
 * 此函数为特定用户检索分页的联系人列表。
 *
 * @param {string} page - 页码，从'1'开始。
 * @param {string} size - 每页返回的联系人数量。
 * @param {string} userId - 要检索联系人列表的用户ID。
 * *
 * @returns {Promise<Object>} 包含HTTP状态码、消息和查询结果的对象。
 *  - code: HTTP状态码，例如，200表示成功，500表示服务器错误。
 *  - msg: 消息，表示操作的结果。
 *  - data: 查询结果，即分页的联系人列表。
 *
 * @throws  {Error} 当执行查询时出现问题时，会抛出错误。
 */
const getContactList = async (
  page: number,
  size: number,
  userId: string,
  keyWord?: string | undefined
) => {
  try {
    let pageSize = Number(size); // Convert size to number
    let offset = (Number(page) - 1) * pageSize; // Calculate offset
    let sql = ``;
    if (keyWord) {
      sql = `
      select t4.friendId,t4.friendName,t4.createTime from (
        SELECT
        CASE
          WHEN
            t1.user_id = '${userId}' THEN
              t1.friend_id ELSE t1.user_id 
              END AS friendId,
          CASE
              WHEN t1.user_id = '${userId}' THEN
              t3.NAME ELSE t2.NAME 
            END AS friendName,
            CASE
              WHEN t1.user_id = '${userId}' THEN
              t3.username ELSE t2.username 
            END AS friendUserName,
            t1.create_time AS createTime 
          FROM
            friends_info t1
            LEFT JOIN user_info t2 ON t1.user_id = t2.id
            LEFT JOIN user_info t3 ON t1.friend_id = t3.id 
          WHERE
          t1.user_id = '${userId}' 
          OR t1.friend_id = '${userId}'
        ) t4 
        where 
        t4.friendName like '%${keyWord}%' 
        or t4.friendId = '${keyWord}'
        or t4.friendUserName = '${keyWord}'
        LIMIT ${pageSize} OFFSET ${offset}
      `;
    } else {
      sql = `
        SELECT 
        CASE
          WHEN t1.user_id = '${userId}' THEN t1.friend_id
          ELSE t1.user_id
        END AS friendId,
        CASE
          WHEN t1.user_id = '${userId}' THEN t3.name
          ELSE t2.name
        END AS friendName,
        t1.create_time as createTime
        FROM 
          friends_info t1
        LEFT JOIN 
          user_info t2 ON t1.user_id = t2.id
        LEFT JOIN 
          user_info t3 ON t1.friend_id = t3.id
        WHERE 
          t1.user_id = '${userId}' OR t1.friend_id = '${userId}'
        LIMIT ${pageSize} OFFSET ${offset}
      `;
    }

    const [result] = await defaultSqlDriver.query(sql);
    return {
      code: 200,
      msg: `获取成功`,
      data: result
    };
  } catch (error) {
    console.error(error);
    return {
      code: 500,
      msg: `服务器错误`,
      data: void 0
    };
  }
};

const getSystemMessage = async (userId: string) => {
  try {
    //查找我接收的系统消息语句
    const queryReceiveMessageSql = `
      select 
      t1.sender_id as senderId,
      t2.\`name\` as senderName,
      t1.receiver_id as receiverId,
      t3.\`name\` as receiverName,
      t1.type,
      t1.\`status\`,
      t1.create_time
      from system_message t1 
      left join user_info t2 on t1.sender_id = t2.id 
      left join user_info t3 on t1.receiver_id = t3.id 
      where t1.receiver_id = ?
    `;

    //查找我发送的系统消息语句
    const querySendMessageSql = `
      select 
      t1.sender_id as senderId,
      t2.\`name\` as senderName,
      t1.receiver_id as receiverId,
      t3.\`name\` as receiverName,
      t1.type,
      t1.\`status\`,
      t1.create_time
      from system_message t1 
      left join user_info t2 on t1.sender_id = t2.id 
      left join user_info t3 on t1.receiver_id = t3.id 
      where t1.sender_id = ?
    `;

    const promises = [
      defaultSqlDriver.query(queryReceiveMessageSql, [userId]),
      defaultSqlDriver.query(querySendMessageSql, [userId])
    ];

    // 并发执行查询
    const [receiveMessage, sendMessage] = await Promise.all(promises);

    return {
      code: 200,
      msg: `获取成功`,
      data: {
        receiveMessage: receiveMessage[0],
        sendMessage: sendMessage[0]
      }
    };
  } catch (error) {
    return {
      code: 500,
      msg: `服务器错误`,
      data: void 0
    };
  }
};


export default {
  login,
  register,
  searchUser,
  addFriend,
  getContactList,
  getSystemMessage
};
